home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 / Ham Radio 2000.iso / ham2000 / tcp_ip / os2 / pmnos11s / pop3serv.c < prev    next >
Text File  |  1993-07-30  |  20KB  |  894 lines

  1. /* POP3 Server state machine - see RFC 1225
  2.  *
  3.  *    Jan 92    Erik Olson olson@phys.washington.edu
  4.  *        Taken from POP2 server code in NOS 910618
  5.  *        Rewritten/converted to POP3
  6.  *    Feb 92    William Allen Simpson
  7.  *        integrated with current work
  8.  *
  9.  *  "Need-to" list: XTND XMIT (to get WinQVTnet to work)
  10.  */
  11. #if defined(OS2)
  12. #define INCL_DOSFILEMGR
  13. #define INCL_NOCOMMON
  14. #include <os2.h>
  15. int stat(PSZ pszPathName, PFILESTATUS3 pStatus);
  16. #endif
  17.  
  18. #include <stdio.h>
  19. #include <fcntl.h>
  20. #include <time.h>
  21. //#include <sys/stat.h>
  22. #if defined(UNIX) || defined(MSDOS)
  23. #include <sys/types.h>
  24. #endif
  25. #if    defined(__STDC__) || defined(__TURBOC__)
  26. #include <stdarg.h>
  27. #endif
  28. #include <ctype.h>
  29. #include <setjmp.h>
  30. #include "global.h"
  31. #include "mbuf.h"
  32. #include "cmdparse.h"
  33. #include "socket.h"
  34. #include "proc.h"
  35. #include "files.h"
  36. #include "smtp.h"
  37.  
  38. /* ---------------- common server data structures ---------------- */
  39. /* POP message pointer element */
  40.  
  41. struct pop_msg {
  42.     long len;
  43.     long pos;
  44.     int deleted;
  45.     struct pop_msg *next;
  46. };
  47.  
  48. /* POP server control block */
  49.  
  50. struct pop_scb {
  51.     int socket;        /* socket number for this connection */
  52.     char state;        /* server state */
  53. #define      LSTN    0
  54. #define      AUTH    1
  55. #define      TRANS    2
  56. #define      UPDATE    3
  57. #define      DONE    5
  58.  
  59.     char    buf[TLINELEN];     /* input line buffer */
  60.     char    count;        /* line buffer length */
  61.     char    username[64];    /* user/folder name */
  62.     FILE    *wf;        /* work folder file pointer */
  63.     int    folder_len;    /* number of msgs in current folder */
  64.     int    high_num;    /* highest message number accessed */
  65.     long    folder_file_size; /* length of the current folder file, in bytes */
  66.     char    folder_modified; /* mail folder contents modified flag */
  67.     struct pop_msg *msg;    /* message database link-list */
  68. };
  69.  
  70. #define NULLSCB  (struct pop_scb *)0
  71.  
  72. /* Response messages */
  73.  
  74. static char    count_rsp[]    = "+OK you have %d messages\r\n",
  75.         error_rsp[]    = "-ERR %s\r\n",
  76.         greeting_msg[]    = "+OK %s POP3 ready\r\n",
  77.         user_rsp[]    = "+OK user\r\n",
  78.         pass_rsp[]    = "+OK password\r\n",
  79.         stat_rsp[]    = "+OK %d %ld\r\n",
  80.         list_single_rsp[]    = "+OK %d %d\r\n",
  81.         list_multi_rsp[]    = "+OK %d messages (%ld octets)\r\n",
  82.         retr_rsp[]    = "+OK %ld octets\r\n",
  83.         multi_end_rsp[] = ".\r\n",
  84.         msg_line[]    = "%s\r\n",
  85.         dele_rsp[]    = "+OK message %d deleted\r\n",
  86.         noop_rsp[]    = "+OK\r\n",
  87.         last_rsp[]    = "+OK %d\r\n",
  88.         signoff_msg[]    = "+OK Bye, bye-bye, bye now, goodbye\r\n";
  89.  
  90. static void rrip __ARGS((char *s));
  91. static struct pop_scb *create_scb __ARGS((void));
  92. static void delete_scb __ARGS((struct pop_scb *scb));
  93. static void popserv __ARGS((int s,void *unused,void *p));
  94. static int poplogin __ARGS((char *pass,char *username));
  95.  
  96. static void pop_sm __ARGS((struct pop_scb *scb));
  97.  
  98. static int Spop = -1; /* prototype socket for service */
  99.  
  100.  
  101. /* Start up POP receiver service */
  102. int
  103. pop3start(argc,argv,p)
  104.  
  105. int argc;
  106. char *argv[];
  107. void *p;
  108.  
  109. {
  110.     struct sockaddr_in lsocket;
  111.     int s;
  112.  
  113.     if (Spop != -1) {
  114.         return 0;
  115.     }
  116.  
  117.     psignal(Curproc,0);    /* Don't keep the parser waiting */
  118.     chname(Curproc,"POP3 listener");
  119.  
  120.     lsocket.sin_family = AF_INET;
  121.     lsocket.sin_addr.s_addr = INADDR_ANY;
  122.     if(argc < 2)
  123.         lsocket.sin_port = IPPORT_POP3;
  124.     else
  125.         lsocket.sin_port = atoi(argv[1]);
  126.  
  127.     Spop = socket(AF_INET,SOCK_STREAM,0);
  128.  
  129.     bind(Spop,(char *)&lsocket,sizeof(lsocket));
  130.  
  131.     listen(Spop,1);
  132.  
  133.     for (;;) {
  134.         if((s = accept(Spop,NULLCHAR,(int *)NULL)) == -1)
  135.             break;    /* Service is shutting down */
  136.  
  137.         /* Spawn a server */
  138.  
  139.         newproc("POP3 server",2048,popserv,s,NULL,NULL,0);
  140.     }
  141.     return 0;
  142. }
  143.  
  144. /* Shutdown POP3 service (existing connections are allowed to finish) */
  145.  
  146. int
  147. pop3stop(argc,argv,p)
  148. int argc;
  149. char *argv[];
  150. void *p;
  151.  
  152. {
  153.     close_s(Spop);
  154.     Spop = -1;
  155.     return 0;
  156. }
  157.  
  158. static void
  159. popserv(s,unused,p)
  160. int s;
  161. void *unused;
  162. void *p;
  163. {
  164.     struct pop_scb *scb;
  165.  
  166.     sockowner(s,Curproc);        /* We own it now */
  167.     log(s,"open POP3");
  168.  
  169.     if((scb = create_scb()) == NULLSCB) {
  170.         tprintf(Nospace);
  171.         log(s,"close POP3 - no space");
  172.         close_s(s);
  173.         return;
  174.     }
  175.  
  176.     scb->socket = s;
  177.     scb->state  = AUTH;
  178.  
  179.     (void) usprintf(s,greeting_msg,Hostname);
  180.  
  181. loop:    if ((scb->count = recvline(s,scb->buf,TLINELEN)) == -1){
  182.         /* He closed on us */
  183.  
  184.         goto quit;
  185.     }
  186.  
  187.     rip(scb->buf);
  188.     if (strlen(scb->buf) == 0)    /* Ignore blank cmd lines */
  189.         goto loop;
  190.     pop_sm(scb);
  191.     if (scb->state == DONE)
  192.         goto quit;
  193.  
  194.     goto loop;
  195.  
  196. quit:
  197.     log(scb->socket,"close POP3");
  198.     close_s(scb->socket);
  199.     delete_scb(scb);
  200. }
  201.  
  202.  
  203. /* Create control block, initialize */
  204.  
  205. static struct
  206. pop_scb *create_scb()
  207. {
  208.     register struct pop_scb *scb;
  209.  
  210.     if((scb = (struct pop_scb *)callocw(1,sizeof (struct pop_scb))) == NULLSCB)
  211.         return NULLSCB;
  212.  
  213.     scb->username[0] = '\0';
  214.     scb->msg = NULL;
  215.     scb->wf = NULL;
  216.  
  217.     scb->count = scb->folder_file_size = 0;
  218.  
  219.     scb->folder_modified = FALSE;
  220.     return scb;
  221. }
  222.  
  223.  
  224. /* Free msg link-list */
  225. static void
  226. delete_msglist(struct pop_msg *b_msg)
  227. {
  228.     struct pop_msg *msg,*msg2;
  229.     msg=b_msg;
  230.     while(msg!=NULL) {msg2=msg->next; free(msg); msg=msg2;}
  231. }
  232.  
  233. /* Free resources, delete control block */
  234.  
  235. static void
  236. delete_scb(scb)
  237. register struct pop_scb *scb;
  238. {
  239.     if (scb == NULLSCB)
  240.         return;
  241.     if (scb->wf != NULL)
  242.         fclose(scb->wf);
  243.     if (scb->msg  != NULL)
  244.         delete_msglist(scb->msg);
  245.  
  246.     free((char *)scb);
  247. }
  248.  
  249. /* replace terminating end of line marker(s) (\r and \n) with null,
  250.             and change . to .. */
  251. static void
  252. rrip(s)
  253. register char *s;
  254. {
  255.     register char *cp;
  256.  
  257.     if((cp = strchr(s,'\r')) != NULLCHAR)
  258.         *cp = '\0';
  259.     if((cp = strchr(s,'\n')) != NULLCHAR)
  260.         *cp = '\0';
  261. }
  262.  
  263. /* --------------------- start of POP server code ------------------------ */
  264.  
  265. #define BITS_PER_WORD    16
  266.  
  267. #define isSOM(x)    ((strncmp(x,"From ",5) == 0))
  268.  
  269. /* Command string specifications */
  270.  
  271. static char
  272.         user_cmd[] = "USER ",
  273.         pass_cmd[] = "PASS ",
  274.         quit_cmd[] = "QUIT",
  275.         stat_cmd[] = "STAT",
  276.         list_cmd[] = "LIST",
  277.         retr_cmd[] = "RETR",
  278.         dele_cmd[] = "DELE",
  279.         noop_cmd[] = "NOOP",
  280.         rset_cmd[] = "RSET",
  281.         top_cmd[]  = "TOP",
  282.         last_cmd[] = "LAST";
  283.  
  284. static void
  285. pop_sm(scb)
  286. struct pop_scb *scb;
  287. {
  288.     char password[40];
  289.  
  290.     void state_error(struct pop_scb *,char *);
  291.     void fatal_error(struct pop_scb *,char *);
  292.     void open_folder(struct pop_scb *);
  293.     void do_cleanup(struct pop_scb *);
  294.     void stat_message(struct pop_scb *);
  295.     void list_message(struct pop_scb *);
  296.     void retr_message(struct pop_scb *);
  297.     void dele_message(struct pop_scb *);
  298.     void noop_message(struct pop_scb *);
  299.     void last_message(struct pop_scb *);
  300.     void rset_message(struct pop_scb *);
  301.     void top_message(struct pop_scb *);
  302.     void close_folder(struct pop_scb *);
  303.  
  304.     if (scb == NULLSCB) /* be certain it is good -- wa6smn */
  305.         return;
  306.  
  307.     switch(scb->state) {
  308.  
  309.     case AUTH:
  310.         if (strncmp(scb->buf,user_cmd,strlen(user_cmd)) == 0){
  311.             sscanf(scb->buf,"USER %s",scb->username);
  312.             (void) usprintf(scb->socket,user_rsp);
  313.  
  314.         } else if (strncmp(scb->buf,pass_cmd,strlen(pass_cmd)) == 0){
  315.             sscanf(scb->buf,"PASS %s",password);
  316.  
  317.             if (!poplogin(scb->username,password)) {
  318.                 log(scb->socket,"POP3 access DENIED to %s",
  319.                         scb->username);
  320.                 state_error(scb,"Access DENIED!!");
  321.                 return;
  322.             }
  323.  
  324.             log(scb->socket,"POP3 access granted to %s",
  325.                     scb->username);
  326.             open_folder(scb);
  327.         } else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0){
  328.             do_cleanup(scb);
  329.         } else
  330.             state_error(scb,"(AUTH) expected USER, PASS or QUIT");
  331.         break;
  332.  
  333.     case TRANS:
  334.         if (strncmp(scb->buf,stat_cmd,strlen(stat_cmd)) == 0)
  335.             stat_message(scb);
  336.  
  337.         else if (strncmp(scb->buf,list_cmd,strlen(list_cmd)) == 0)
  338.             list_message(scb);
  339.  
  340.         else if (strncmp(scb->buf,retr_cmd,strlen(retr_cmd)) == 0)
  341.             retr_message(scb);
  342.  
  343.         else if (strncmp(scb->buf,dele_cmd,strlen(dele_cmd)) == 0)
  344.             dele_message(scb);
  345.  
  346.         else if (strncmp(scb->buf,last_cmd,strlen(noop_cmd)) == 0)
  347.             noop_message(scb);
  348.  
  349.         else if (strncmp(scb->buf,last_cmd,strlen(last_cmd)) == 0)
  350.             last_message(scb);
  351.  
  352.         else if (strncmp(scb->buf,top_cmd,strlen(top_cmd)) == 0)
  353.             top_message(scb);
  354.  
  355.         else if (strncmp(scb->buf,rset_cmd,strlen(rset_cmd)) == 0)
  356.             rset_message(scb);
  357.  
  358.         else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0)
  359.             do_cleanup(scb);
  360.  
  361.         else
  362.             state_error(scb,
  363.                     "(TRANS) unsupported/unrecognized command");
  364.         break;
  365.  
  366.     case DONE:
  367.         break;
  368.  
  369.     default:
  370.         fatal_error(scb,"(TOP) State Error!!");
  371.         break;
  372.     }
  373. }
  374.  
  375. static void
  376. do_cleanup(scb)
  377. struct pop_scb *scb;
  378. {
  379.     void close_folder(struct pop_scb *);
  380.  
  381.     close_folder(scb);
  382.     (void) usprintf(scb->socket,signoff_msg);
  383.     scb->state = DONE;
  384. }
  385.  
  386. static void
  387. state_error(scb,msg)
  388. struct pop_scb *scb;
  389. char *msg;
  390. {
  391.     (void) usprintf(scb->socket,error_rsp,msg);
  392.     /* scb->state = DONE; */  /* Don't automatically hang up */
  393. }
  394.  
  395. static void
  396. fatal_error(scb,msg)
  397. struct pop_scb *scb;
  398. char *msg;
  399. {
  400.     (void) usprintf(scb->socket,error_rsp,msg);
  401.     scb->state = DONE;
  402. }
  403.  
  404. static void
  405. close_folder(scb)
  406. struct pop_scb *scb;
  407. {
  408.     char folder_pathname[64];
  409.     char line[TLINELEN];
  410.     FILE *fd;
  411.     int deleted = FALSE;
  412.     int msg_no = 0;
  413.     struct pop_msg *msg;
  414.     int newmail(struct pop_scb *);
  415.     void state_error(struct pop_scb *,char *);
  416.     void fatal_error(struct pop_scb *,char *);
  417.  
  418.  
  419.     if (scb->wf == NULL)
  420.         return;
  421.  
  422.     if (!scb->folder_modified) {
  423.         /* no need to re-write the folder if we have not modified it */
  424.  
  425.         fclose(scb->wf);
  426.         scb->wf = NULL;
  427.  
  428.         delete_msglist(scb->msg);
  429.         scb->msg=NULL;
  430.         return;
  431.     }
  432.  
  433.  
  434.     sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  435.  
  436.     if (newmail(scb)) {
  437.         /* copy new mail into the work file and save the
  438.                     message count for later */
  439.  
  440.         if ((fd = fopen(folder_pathname,"r")) == NULL) {
  441.             fatal_error(scb,"Unable to add new mail to folder");
  442.             return;
  443.         }
  444.  
  445.         fseek(scb->wf,0,SEEK_END);
  446.         fseek(fd,scb->folder_file_size,SEEK_SET);
  447.         while (!feof(fd)) {
  448.             fgets(line,TLINELEN,fd);
  449.             fputs(line,scb->wf);
  450.         }
  451.  
  452.         fclose(fd);
  453.     }
  454.  
  455.     /* now create the updated mail folder */
  456.  
  457.     if ((fd = fopen(folder_pathname,"w")) == NULL){
  458.         fatal_error(scb,"Unable to update mail folder");
  459.         return;
  460.     }
  461.  
  462.     rewind(scb->wf);
  463.     msg=scb->msg;
  464.     while (!feof(scb->wf)){
  465.         fgets(line,TLINELEN,scb->wf);
  466.  
  467.         if (isSOM(line)){
  468.             if (msg!=NULL) msg=msg->next;
  469.             msg_no++;
  470.             if (msg!=NULL)
  471.                 deleted = msg->deleted;
  472.             else
  473.                 deleted = FALSE;
  474.         }
  475.  
  476.         if (deleted)
  477.             continue;
  478.  
  479.         fputs(line,fd);
  480.     }
  481.  
  482.     fclose(fd);
  483.     fclose(scb->wf);
  484.     scb->wf = NULL;
  485.     delete_msglist(scb->msg);
  486.     scb->msg=NULL;
  487.  
  488. }
  489.  
  490. static void
  491. open_folder(scb)
  492. struct pop_scb *scb;
  493. {
  494. #if !defined(OS2)
  495.     char folder_pathname[64];
  496. #else
  497.    char folder_pathname[256];
  498. #endif
  499.     char line[TLINELEN];
  500.     long pos;
  501.     FILE *fd;
  502.     FILE *tmpfile();
  503. #if !defined(OS2)
  504.     struct stat folder_stat;
  505. #else
  506.    FILESTATUS3 folder_stat;
  507. #endif
  508.     struct pop_msg *msg;
  509.  
  510.     sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  511.     scb->folder_len       = 0;
  512.     scb->folder_file_size = 0;
  513.     if (stat(folder_pathname,&folder_stat)){
  514.         (void) usprintf(scb->socket,count_rsp,scb->folder_len);
  515.         scb->state  = TRANS;
  516.         return;     /* no file = OK */
  517.     }
  518. #if !defined(OS2)
  519.     scb->folder_file_size = folder_stat.st_size;
  520. #else
  521.    scb->folder_file_size = folder_stat.cbFile;
  522. #endif
  523.     if ((fd = fopen(folder_pathname,"r")) == NULL){
  524.         state_error(scb,"Unable to open mail folder");
  525.         return;
  526.     }
  527.  
  528.     if ((scb->wf = tmpfile()) == NULL) {
  529.         state_error(scb,"Unable to create work folder");
  530.         return;
  531.     }
  532.  
  533.     scb->msg=calloc(sizeof(struct pop_msg),1); /* create first element */
  534.     if (scb->msg==NULL)
  535.     {
  536.         fatal_error(scb,"Unable to create pointer list");
  537.         return;
  538.     }
  539.     scb->msg->next=NULL;
  540.     msg=scb->msg;
  541.     msg->len=0;
  542.     msg->deleted=0;
  543.  
  544.     while(!feof(fd)) {
  545.         pos=ftell(scb->wf);
  546.         fgets(line,TLINELEN,fd);
  547.  
  548.         /* scan for begining of a message */
  549.  
  550.         if (isSOM(line))
  551.         {
  552.             scb->folder_len++;
  553.             msg->next=calloc(sizeof(struct pop_msg),1);
  554.             if (msg->next==NULL)
  555.             {
  556.                 fatal_error(scb,
  557.                         "Unable to create pointer list");
  558.                 return;
  559.             }
  560.             msg=msg->next;
  561.             msg->pos=pos;
  562.             msg->next=NULL;
  563.             msg->len=0;
  564.             msg->deleted=0;
  565.  
  566.         /* now put  the line in the work file */
  567.         }
  568.         fputs(line,scb->wf);
  569.         rrip(line);
  570.         if ( *line == '.' ) msg->len++;
  571.         msg->len +=strlen(line)+2; /* Add msg len count */
  572.     }
  573.  
  574.     fclose(fd);
  575.     scb->high_num=0;  /* reset high read */
  576.  
  577.     (void) usprintf(scb->socket,count_rsp,scb->folder_len);
  578.  
  579.     scb->state  = TRANS;
  580. }
  581.  
  582. static void
  583. stat_message(scb)
  584. struct pop_scb *scb;
  585. {
  586.     long total=0;
  587.     int count=0;
  588.     struct pop_msg *msg;
  589.  
  590.     if (scb == NULLSCB) /* check for null -- wa6smn */
  591.         return;
  592.  
  593.     if (scb->folder_len)    /* add everything up */
  594.         for (msg=scb->msg->next; msg!=NULL; msg=msg->next)
  595.             if (!msg->deleted)
  596.                 {    total += msg->len; ++count;}
  597.  
  598.     (void) usprintf(scb->socket,stat_rsp,count,total);
  599. }
  600.  
  601. static void
  602. list_message(scb)
  603. struct pop_scb *scb;
  604. {
  605.     struct pop_msg *msg;
  606.     int msg_no=0;
  607.     long total=0;
  608.     struct pop_msg *goto_msg(struct pop_scb *,int );
  609.  
  610.     if (scb == NULLSCB) /* check for null -- wa6smn */
  611.         return;
  612.     if (scb->buf[sizeof(list_cmd) - 1] == ' ')
  613.     {
  614.         msg_no = atoi(&(scb->buf[sizeof(list_cmd) - 1]));
  615.         msg=goto_msg(scb,msg_no);
  616.         if (msg==NULL || msg->deleted)
  617.             state_error(scb,"non existent or deleted message");
  618.         else
  619.             (void) usprintf(scb->socket,list_single_rsp,
  620.             msg_no,msg->len);
  621.     } else    /* multiline */
  622.     {
  623.         if (scb->folder_len)        /* add everything */
  624.             for (msg=scb->msg->next; msg!=NULL;msg=msg->next)
  625.                 if (!msg->deleted)
  626.         total += msg->len,++msg_no;
  627.  
  628.         (void) usprintf(scb->socket,list_multi_rsp,
  629.                 msg_no,total);
  630.  
  631.         if (scb->folder_len)
  632.             for (msg=scb->msg->next,msg_no=1; msg!=NULL;
  633.                     msg=msg->next,msg_no++)
  634.                 if (!msg->deleted) {
  635.                     (void) usprintf(scb->socket,"%d %ld\r\n",
  636.                         msg_no,msg->len);
  637.                 }
  638.         (void) usprintf(scb->socket,multi_end_rsp);
  639.     }
  640. }
  641.  
  642. static void
  643. retr_message(scb)
  644. struct pop_scb *scb;
  645. {
  646.     char line[TLINELEN];
  647.     long cnt;
  648.     int msg_no;
  649.     struct pop_msg *msg;
  650.     struct pop_msg *goto_msg(struct pop_scb *,int );
  651.  
  652.     if (scb == NULLSCB) /* check for null -- wa6smn */
  653.         return;
  654.     if (scb->buf[sizeof(retr_cmd) - 1] != ' ')
  655.     {
  656.         state_error(scb,"no such message");
  657.         return;
  658.     }
  659.     msg_no = atoi(&(scb->buf[sizeof(retr_cmd) - 1]));
  660.     msg=goto_msg(scb,msg_no);
  661.     if (msg==NULL || msg->deleted) {
  662.         state_error(scb,"no such message");
  663.         return;
  664.     }
  665.  
  666.     cnt  = msg->len;
  667.     (void) usprintf(scb->socket,retr_rsp,cnt);
  668.     fseek(scb->wf,msg->pos,SEEK_SET);  /* Go there */
  669.  
  670.     while(!feof(scb->wf) && (cnt > 0)) {
  671.         fgets(line,TLINELEN,scb->wf);
  672.         rrip(line);
  673.         if ( *line == '.' ) {
  674.             (void) usprintf(scb->socket,".");
  675.             cnt--;
  676.         }
  677.         (void) usprintf(scb->socket,msg_line,line);
  678.         cnt -= (strlen(line)+2); /* Compensate for CRLF */
  679.     }
  680.     (void) usprintf(scb->socket,".\r\n");
  681.     if (msg_no >= scb->high_num)
  682.         scb->high_num=msg_no;      /* bump high water mark */
  683. }
  684.  
  685. static void
  686. noop_message(scb)
  687. struct pop_scb *scb;
  688. {
  689.         (void) usprintf(scb->socket,noop_rsp);
  690. }
  691.  
  692. static void
  693. last_message(scb)
  694. struct pop_scb *scb;
  695. {
  696.     (void) usprintf(scb->socket,last_rsp,scb->high_num);
  697. }
  698.  
  699. static void
  700. rset_message(scb)
  701. struct pop_scb *scb;
  702. {
  703.     struct pop_msg *msg;
  704.     long total=0;
  705.  
  706.     if (scb->folder_len)
  707.         for (msg=scb->msg->next; msg!=NULL; msg=msg->next)
  708.             msg->deleted=FALSE,total+=msg->len;
  709.  
  710.     scb->high_num=0;  /* reset last */
  711.     scb->folder_modified=FALSE;
  712.     (void) usprintf(scb->socket,list_multi_rsp,scb->folder_len,total);
  713. }
  714.  
  715. static void
  716. top_message(scb)
  717. struct pop_scb *scb;
  718. {
  719.     char *ptr;
  720.     char line[TLINELEN];
  721.     struct pop_msg *msg;
  722.     int msg_no=0,lines=0;
  723.     long total=0;
  724.  
  725.     struct pop_msg *goto_msg(struct pop_scb *,int );
  726.  
  727.     if (scb == NULLSCB) /* check for null -- wa6smn */
  728.         return;
  729.     if (scb->buf[sizeof(top_cmd) - 1] != ' ')
  730.     {
  731.         state_error(scb,"No message specified");
  732.         return;
  733.     }
  734.     for (ptr=scb->buf+sizeof(top_cmd); *ptr==' ' ; ++ptr);
  735.         /* Space drop */
  736.     for ( ; *ptr!=' ' && *ptr !='\0'; ++ptr);
  737.         /* token drop */
  738.     msg_no = atoi(&(scb->buf[sizeof(top_cmd) - 1]));
  739.     lines = atoi(++ptr);  /* Get # lines to top */
  740.     if (lines < 0) lines=0;
  741.  
  742.     msg=goto_msg(scb,msg_no);
  743.     if (msg==NULL || msg->deleted)
  744.     {
  745.         state_error(scb,"non existent or deleted message");
  746.         return;
  747.     }
  748.     fseek(scb->wf,msg->pos,SEEK_SET);  /* Go there */
  749.     total=msg->len;  /* Length of current message */
  750.     (void) usprintf(scb->socket,noop_rsp);    /* Give OK */
  751.     do {
  752.         fgets(line,TLINELEN,scb->wf);
  753.         rrip(line);
  754.         if ( *line == '.' ) {
  755.             (void) usprintf(scb->socket,".");
  756.             total--;
  757.         }
  758.         total -= strlen(line)+2;
  759.         (void) usprintf(scb->socket,msg_line,line);
  760.     } while (*line!='\0' && total>0);
  761.     for ( ; total > 0 && lines; --lines) {
  762.         fgets(line,TLINELEN,scb->wf);
  763.         rrip(line);
  764.         if ( *line == '.' ) {
  765.             (void) usprintf(scb->socket,".");
  766.             total--;
  767.         }
  768.         total -= strlen(line)+2;
  769.         (void) usprintf(scb->socket,msg_line,line);
  770.     }
  771.     (void) usprintf(scb->socket,multi_end_rsp);
  772. }
  773.  
  774. static int
  775. poplogin(username,pass)
  776. char *pass;
  777. char *username;
  778. {
  779.     char buf[80];
  780.     char *cp;
  781.     char *cp1;
  782.     FILE *fp;
  783.  
  784.     if((fp = fopen(Popusers,"r")) == NULLFILE) {
  785.         /* User file doesn't exist */
  786.         tprintf("POP users file %s not found\n",Popusers);
  787.         return(FALSE);
  788.     }
  789.  
  790.     while(fgets(buf,sizeof(buf),fp),!feof(fp)) {
  791.         if(buf[0] == '#')
  792.             continue; /* Comment */
  793.  
  794.         if((cp = strchr(buf,':')) == NULLCHAR)
  795.             /* Bogus entry */
  796.             continue;
  797.  
  798.         *cp++ = '\0';  /* Now points to password */
  799.         if(strcmp(username,buf) == 0)
  800.             break;    /* Found user name */
  801.     }
  802.  
  803.     if(feof(fp)) {
  804.         /* User name not found in file */
  805.  
  806.         fclose(fp);
  807.         return(FALSE);
  808.     }
  809.     fclose(fp);
  810.  
  811.     if ((cp1 = strchr(cp,':')) == NULLCHAR)
  812.         return(FALSE);
  813.  
  814.     *cp1 = '\0';
  815.     if(strcmp(cp,pass) != 0) {
  816.         /* Password required, but wrong one given */
  817.  
  818.         return(FALSE);
  819.     }
  820.  
  821.     /* whew! finally made it!! */
  822.  
  823.     return(TRUE);
  824. }
  825.  
  826. static void
  827. dele_message(scb)
  828. struct pop_scb *scb;
  829. {
  830.     struct pop_msg *msg;
  831.     int msg_no;
  832.     struct pop_msg *goto_msg(struct pop_scb *,int );
  833.  
  834.     if (scb == NULLSCB) /* check for null -- wa6smn */
  835.         return;
  836.     if (scb->buf[sizeof(retr_cmd) - 1] != ' ')
  837.     {
  838.         state_error(scb,"no such message");
  839.         return;
  840.     }
  841.     msg_no = atoi(&(scb->buf[sizeof(retr_cmd) - 1]));
  842.     msg=goto_msg(scb,msg_no);
  843.     if (msg==NULL || msg->deleted) {
  844.         state_error(scb,"attempt to access deleted message");
  845.         return;
  846.     }
  847.     if (msg->deleted) /* Don't bother if already dead */
  848.     {
  849.             state_error(scb,"message already deleted");
  850.             return;
  851.     }
  852.     msg->deleted=TRUE;
  853.     scb->folder_modified = TRUE;
  854.     (void) usprintf(scb->socket,dele_rsp,msg_no);
  855. }
  856.  
  857. static int
  858. newmail(scb)
  859. struct pop_scb *scb;
  860. {
  861. #if !defined(OS2)
  862.     char folder_pathname[64];
  863.     struct stat folder_stat;
  864. #else
  865.     char folder_pathname[256];
  866.     FILESTATUS3 folder_stat;
  867. #endif
  868.     sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  869.  
  870.     if (stat(folder_pathname,&folder_stat)) {
  871.         state_error(scb,"Unable to get old mail folder's status");
  872.         return(FALSE);
  873.     } else
  874. #if !defined(OS2)
  875.         return ((folder_stat.st_size > scb->folder_file_size)? TRUE:FALSE);
  876. #else
  877.         return ((folder_stat.cbFile > scb->folder_file_size)? TRUE:FALSE);
  878. #endif
  879. }
  880.  
  881. static struct pop_msg *
  882. goto_msg(struct pop_scb *scb,int msg_no)
  883. {
  884.     int msg_num;
  885.     struct pop_msg *msg;
  886.  
  887.     msg_num=msg_no-1;
  888.     if (scb->folder_len==0 || msg_num < 0)
  889.             return NULL;
  890.     for (msg=scb->msg->next; msg_num && msg!=NULL; --msg_num) msg=msg->next;
  891.     return msg;
  892. }
  893.  
  894.